#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
                            _ooOoo_  
                           o8888888o  
                           88" . "88  
                          (|  -_-  |)  
                           O\  =  /O  
                        ____/`---'\____  
                      .   ' \\| |// `.  
                       / \\||| : |||// \  
                     / _||||| -:- |||||- \  
                       | | \\\ - /// | |  
                     | \_| ''\---/'' | |  
                      \ .-\__ `-` ___/-. /  
                   ___`. .' /--.--\ `. . __  
                ."" '< `.___\_<|>_/___.' >'"".  
               | | : `- \`.;`\ _ /`;.`/ - ` : | |  
                 \ \ `-. \_ __\ /__ _/ .-` / /  
         ======`-.____`-.___\_____/___.-`____.-'======  
                            `=---='  
  
         .............................................  
                  佛祖镇楼                  BUG辟易  
          佛曰:  
                  写字楼里写字间，写字间里程序员；  
                  程序人员写程序，又拿程序换酒钱。  
                  酒醒只在网上坐，酒醉还来网下眠；  
                  酒醉酒醒日复日，网上网下年复年。  
                  但愿老死电脑间，不愿鞠躬老板前；  
                  奔驰宝马贵者趣，公交自行程序员。  
                  别人笑我忒疯癫，我笑自己命太贱；  
                  不见满街漂亮妹，哪个归得程序员？ 
'''
# @File  : connectionModbusSlave2.py
# @Author: huguangzhi
# @Drivce: Thinkpad E470
# @ContactEmail : huguangzhi@ucsdigital.com.com 
# @ContactPhone : 13121961510 
# @Date  : 2021/9/30 - 14:24
# @Desc  :

# @Author: huguangzhi
# @design: E480
# @ContactEmail : huguangzhi@ucsdigital.com.com
# @ContactPhone : 13121961510
# @Desc  : 通过modbus链接三亚的电梯设备，完成数据的获取
import datetime
import os
import traceback

from pymodbus.client.sync import ModbusTcpClient
import logging
import logging.config
import time
import pymysql

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
LOG_DIR = os.path.join(BASE_DIR, "logs")
if not os.path.exists(LOG_DIR):
    os.makedirs(LOG_DIR)  # 创建路径

LOG_FILE = datetime.datetime.now().strftime("%Y-%m-%d") + ".log"

LOGGING = {
    "version": 1,
    "disable_existing_loggers": False,
    "formatters": {
        "simple": {
            'format': '%(asctime)s [%(name)s:%(lineno)d] [%(levelname)s]- %(message)s'
        },
        'standard': {
            'format': '%(asctime)s [%(threadName)s:%(thread)d] [%(name)s:%(lineno)d] [%(levelname)s]- %(message)s'
        },
    },

    "handlers": {
        "console": {
            "class": "logging.StreamHandler",
            "level": "DEBUG",
            "formatter": "simple",
            "stream": "ext://sys.stdout"
        },

        "default": {
            "class": "logging.handlers.RotatingFileHandler",
            "level": "INFO",
            "formatter": "simple",
            "filename": os.path.join(LOG_DIR, LOG_FILE),
            'mode': 'w+',
            "maxBytes": 1024*1024*5,  # 5 MB
            "backupCount": 20,
            "encoding": "utf8"
        },
    },

    "loggers": {
        "app_name": {
            "level": "INFO",
            "handlers": ["console"],
            "propagate": "no"
        }
    },

    "root": {
        'handlers': ['default'],
        'level': "INFO",
        'propagate': False
    }
}

logging.config.dictConfig(LOGGING)



def catch_except(func):
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except Exception:
            error_info = traceback.format_exc()
            callable(func(*args,**kwargs))
            logging.error(error_info)
            return "COUNT ERROR"

    return wrapper


@catch_except
class GetLiftData():
    # modbus 配置信息

    host = "10.171.28.31"
    port = 8787
    start_address = 64
    query_size = 2
    sleep_time = 0.01
    # 数据库配置信息
    mysql_host = "192.168.30.115"
    mysql_port = 3306
    mysql_db = "lift_pro"
    mysql_user = "lift"
    mysql_passwd = "lift"
    mysql_table = "modbus_lift_sec"





    def __init__(self):

        self.db = pymysql.connect(host=self.mysql_host,
                                  user=self.mysql_user,
                                  password=self.mysql_passwd,
                                  database=self.mysql_db,
                                  port=self.mysql_port)
        self.cursor = self.db.cursor()
        self.client = ModbusTcpClient(self.host,self.port)

    @catch_except
    def getData(self,address,count):
        try:
            info =  self.client.read_holding_registers(address,count)
            return info.registers
        except:
            return []

    def transoformData(self,info):
        register_65 = '%x'%info[0]
        result = {"stay_floor":str(int(register_65[:-2],16))} # 寄存器65H的结果，表示当前电梯处在的实际层数
        bin_info = [bin(a)[2:].zfill(16) for a in info]
        register_65_L = bin_info[0][8:][::-1]
        result["open_door"] = register_65_L[0]  # 门开 1
        result["on_driver"] = register_65_L[1] # 司机状态
        result["on_stand"] = register_65_L[2] # 独立
        result["for_protection"] = register_65_L[3] # 消防专用
        result["on_overhaul"] = register_65_L[4] # 检修
        result["comprehensive_error"] = register_65_L[5] # 综合故障
        result["on_up"] = register_65_L[7] # 上行
        result["on_down"] = register_65_L[6] # 下行
        register_66_H = bin_info[1][:-8][::-1]
        result["on_service"] = register_66_H[0] # 服务中
        result["keep_communcate"] = register_66_H[1] #保持通信
        result["maintenance_status"] = register_66_H[2] # 维保状态
        result["on_overload"] = register_66_H[3] # 超载
        result["automatic_running"] = register_66_H[4] # 自动运行
        result["box_traveling"] = register_66_H[5] # 轿厢走行
        result["on_earthquake"] = register_66_H[6] # 地震
        result["safety_circuit"] = register_66_H[7] # 安全回路
        register_66_L = bin_info[1][8:][::-1]
        result["backup_power"] = register_66_L[3] # 后备电源
        result["normal_power"] = register_66_L[4] # 正常电源
        result["fire_return_complete"] = register_66_L[6] # 消防返回到位
        result["fire_return"] = register_66_L[7] # 消防返回
        return result

    def execSQL(self,sql):
        try:
            # 执行sql语句
            self.cursor.execute(sql)
            # 提交到数据库执行
            self.db.commit()
            return_data =  self.cursor.fetchall()
        except:
            # 如果发生错误则回滚
            self.db.rollback()
            return_data = None

        return return_data

    def createSQL(self, data:dict):
        key_str = ",".join(data.keys())
        value_str = ""
        for key in data.keys():
            value_str += "'" + data[key] + "',"
        sql = "insert into {0} ({1}) values ({2});".format(
            self.mysql_table,
            key_str,
            value_str[:-1]
        )
        return sql

    def checkTable(self):
        sql = "show tables like '{0}'".format(self.mysql_table)
        if self.execSQL(sql):
            logging.info("数据表存在，匹配正常")
            return 1
        else:
            sql = ""
            try:
                self.execSQL(sql)
                return 1
            except:
                logging.error("无法创建数据表")
            return 0

    def run(self):
        resp = {"code": 1}
        tmp_data = None
        self.checkTable()
        while resp["code"] == 1:
            cache_data = self.getData(self.start_address, self.query_size)
            gett_imestamp = str(int(time.time() * 1000))
            if cache_data:
                if cache_data == tmp_data:
                    # 两个数字相等，不做处理
                    logging.debug("数据相同")
                else:
                    # 两次获取的内容不同
                    # todo 1 数据转化
                    t1_data = self.transoformData(cache_data)
                    t1_data["get_timestamp"] = gett_imestamp
                    # todo 2 构建sql
                    t2_sql = self.createSQL(t1_data)
                    # todo 3 数据存储
                    try:
                        t3_save = self.execSQL(t2_sql)
                        logging.info("数据已经存储到数据表，十进制数据内容为：{},".format(cache_data))
                    except Exception as e:
                        logging.error("数据存储异常，数据内容为：{0}。异常原因是{1}".format(t1_data,e))
                    # 记录当前获取的内容
                    tmp_data = cache_data
            else:
                # resp["code"] = 0

                logging.error("无法获取结果")
                continue
            time.sleep(self.sleep_time)








lift = GetLiftData()
lift.run()